from datetime import datetime
from typing import Optional
from uuid import UUID, uuid4

from bisheng.database.base import session_getter
from bisheng.database.models.base import SQLModelSerializable
from sqlalchemy import Column, DateTime, String, Text, text, desc, func
from sqlalchemy.dialects.mysql import MEDIUMTEXT
from sqlmodel import Field, SQLModel


class AlarmRecordBase(SQLModelSerializable):
    id: UUID = Field(nullable=False, primary_key=True, description='唯一ID')
    message_type: str = Field(sa_column=Column(String(length=255), default=""), description='消息的类型，表示此消息是关于状态量变位的通知')
    alarm_time: Optional[datetime] = Field(
        sa_column=Column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP')))
    alarm_level: str = Field(sa_column=Column(String(length=255), default=''), description='告警级别')
    station: str = Field(sa_column=Column(String(length=255), default=''), description='站点信息，表明该事件所属的站点')
    equipment: str = Field(sa_column=Column(String(length=255), default=''), description='设备名称，表示发生变位的设备')
    switch: str = Field(sa_column=Column(String(length=255), default=''), description='设备名称，表示发生变位的设备')
    point: str = Field(sa_column=Column(String(length=255), default=''), description='测点信息，描述当前变位的具体点位')
    description: str = Field(sa_column=Column(String(length=255), default=''), description='报文原始描述信息')
    location: str = Field(sa_column=Column(String(length=255), default=''), description='设备位置，描述当前设备所在的具体位置')
    status: str = Field(sa_column=Column(String(length=255), default=''),description='当前的状态值，表明开关的状态')
    switch_order: str = Field(sa_column=Column(String(length=255), default=''),description='开关操作指令，此处为空，表示未关联具体操作指令，可忽略')
    IO_AI_detail: str = Field(sa_column=Column(Text),description='详细的IO/AI数据，提供与事件相关的电流、电压等详细信息')
    message_list: str = Field(sa_column=Column(MEDIUMTEXT),description='报文相关，提供与告警相关的报文消息列表')
    message_list_url: str = Field(sa_column=Column(String(length=255), default=''),description='报文url')
    group_id: str = Field(sa_column=Column(String(length=255), default=''), description='告警组ID')
    alarm_number: Optional[int] = Field(index=False, default=0, description='告警编号')
    type: str = Field(sa_column=Column(String(length=255),default='message'),description='message or alarm or sync_alarm')
    waveform_url: str = Field(sa_column=Column(String(length=255), default=''), description='波形url')
    equipment_principle_url: str = Field(sa_column=Column(String(length=255), default=''), description='设备原理url')
    logic_relation_url: str = Field(sa_column=Column(String(length=255), default=''), description='逻辑关系url')
    stage: str = Field(sa_column=Column(Text), description='状态机及缓存')
    alarm_end_time: Optional[datetime] = Field(
        sa_column=Column(DateTime, nullable=True))
    create_time: Optional[datetime] = Field(
        sa_column=Column(DateTime, nullable=False, server_default=text('CURRENT_TIMESTAMP')))
    update_time: Optional[datetime] = Field(sa_column=Column(DateTime,
                                                             nullable=False,
                                                             index=True,
                                                             server_default=text('CURRENT_TIMESTAMP'),
                                                             onupdate=text('CURRENT_TIMESTAMP')))


class AlarmRecord(AlarmRecordBase, table=True):
    id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True)


class AlarmRecordDao:
    @staticmethod
    def create_alarm_record(alarm_record: AlarmRecord) -> AlarmRecord:
        with session_getter() as session:
            # 确保 alarm_record 有一个 UUID
            if not alarm_record.id:
                alarm_record.id = uuid4()
            if not alarm_record.group_id:
                alarm_record.group_id = str(alarm_record.id)
            if not alarm_record.type:
                alarm_record.type = "sync_alarm"

            session.add(alarm_record)
            session.commit()
            session.refresh(alarm_record)
            return alarm_record

    @staticmethod
    def create_message(alarm_record: AlarmRecord) -> AlarmRecord:
        with session_getter() as session:
            if not alarm_record:
                alarm_record.id = uuid4()
            alarm_record.type = "message"
            session.add(alarm_record)
            session.commit()
            session.refresh(alarm_record)
            return alarm_record

    @staticmethod
    def get_alarm_record_by_type(type: str = None, limit: int = None):
        """
        根据类型获取报警记录
        :param type: 报警类型，默认为 None（表示不限制类型）
        :param limit: 返回的记录条数，默认为 None（表示不限制条数）
        :return: 报警记录列表
        """
        with session_getter() as session:
            query = session.query(AlarmRecord).order_by(desc(AlarmRecord.create_time))

            # 如果 type 不为空，添加类型过滤条件
            if type:
                query = query.filter(AlarmRecord.type == type)

            # 如果 limit 不为空，添加条数限制
            if limit is not None:
                query = query.limit(limit)

            return query.all()

    @staticmethod
    def get_alarm_record_list_by_num(num):
        with session_getter() as session:
            query = session.query(AlarmRecord).filter(AlarmRecord.type == 'alarm').order_by(desc(AlarmRecord.create_time))

            if num is None:
                # 如果 num 是 None，返回所有记录
                return query.all()
            elif num > 0:
                # 如果 num 大于 0，返回倒序第 num 条记录，并将其放入列表
                record = query.offset(num - 1).first()
                return [record] if record else []
            else:
                # 如果 num 小于等于 0，返回空列表
                return []

    @staticmethod
    def get_alarm_record_group_by_num(num):
        with session_getter() as session:
            if num is not None and num > 0:
                # 子查询：获取最新的 group_id
                latest_group_subquery = session.query(
                    AlarmRecord.group_id,
                    func.max(AlarmRecord.create_time).label('max_create_time')
                ).filter(AlarmRecord.alarm_number == num and AlarmRecord.type == 'alarm').group_by(AlarmRecord.group_id).order_by(desc('max_create_time')).limit(1).subquery()

                # 查询最新 group 的所有记录
                query = session.query(AlarmRecord).join(
                    latest_group_subquery,
                    AlarmRecord.group_id == latest_group_subquery.c.group_id
                )

                return query.all()
            else:
                query = session.query(AlarmRecord).filter(AlarmRecord.type == 'alarm').order_by(desc(AlarmRecord.create_time)).limit(20)
                return query.all()


    @staticmethod
    def get_alarm_record_by_id(alarm_id: str) -> AlarmRecord:
        with session_getter() as session:
            query = session.query(AlarmRecord).filter(AlarmRecord.id == alarm_id and AlarmRecord.type == 'alarm')
            return query.first()

    @staticmethod
    def get_alarm_record_by_group_id(group_id: str):
        with session_getter() as session:
            query = session.query(AlarmRecord).filter(AlarmRecord.group_id == group_id)
            return query.all()

    @staticmethod
    def get_alarm_number():
        with session_getter() as session:
            latest_record = session.query(AlarmRecord).filter(AlarmRecord.type == 'alarm').order_by(desc(AlarmRecord.create_time)).first()
            if latest_record is None:
                return 1
            else:
                return (latest_record.alarm_number % 8) + 1

    @staticmethod
    def update_alarm_end_time(group_id: str, alarm_end_time: Optional[datetime]) -> Optional[AlarmRecord]:
        """
        更新告警记录的 alarm_end_time。
        Args:
            alarm_id: 要更新的告警记录的 UUID。
            alarm_end_time: 新的 alarm_end_time 值 (可以是 datetime 对象或 None)。
        Returns:
            如果找到并成功更新告警记录，则返回更新后的 AlarmRecord 对象。
            如果没有找到告警记录，则返回 None。
        """
        with session_getter() as session:
            query = session.query(AlarmRecord).filter(AlarmRecord.group_id == group_id and AlarmRecord.type == 'alarm')
            alarm_records = query.all()
            if not alarm_records:
                return None  # 没有找到告警记录
            for alarm_record in alarm_records:
                alarm_record.alarm_end_time = alarm_end_time
            session.commit()  # 只提交一次
            for alarm_record in alarm_records:
                session.refresh(alarm_record)  # refresh all objects
            return alarm_records

    @staticmethod
    def update_alarm_stage(group_id: str, stage: Optional[str]) -> Optional[AlarmRecord]:
        with session_getter() as session:
            query = session.query(AlarmRecord).filter(AlarmRecord.group_id == group_id and AlarmRecord.type == 'alarm')
            alarm_records = query.all()
            if not alarm_records:
                return None  # 没有找到告警记录
            for alarm_record in alarm_records:
                alarm_record.stage = stage
            session.commit()  # 只提交一次
            for alarm_record in alarm_records:
                session.refresh(alarm_record)  # refresh all objects
            return alarm_records


